//! Average distance between 2 vertices
uniform float f_avg_dist;
//! Constant calculated from FOV and window width
uniform float f_fconst;

//! Vertex normal
varying vec3 v_normal;

void main()
{
    // Get camera position
    vec4 camera_pos = gl_ModelViewMatrixInverse [3];
    // Get inverse camera view vector
    vec3 camera_vec = normalize( gl_Vertex.xyz - camera_pos.xyz );

    // If the normal is either facing away from us or it's invalid, we'll mark the fragments red
    if ( dot( gl_Normal, camera_vec ) < 0.0 ||
         gl_Normal.x < -1.0 || gl_Normal.x > 1.0 ||
         gl_Normal.y < -1.0 || gl_Normal.y > 1.0 ||
         gl_Normal.z < -1.0 || gl_Normal.z > 1.0 ) {

        gl_FrontColor = vec4( 1.0, 0.0, 0.0, 1.0 );
    } else {
        // Calculate splat size for the vertex
        float splat_radius = distance( gl_Vertex, camera_pos ) * f_fconst;
        // Calculate splat size
        //  0.002 / splat_radius = point size in close range (determined by pixel error)
        //  1600.0 * f_avg_dist = point size determined by average distance (far range)
        //gl_PointSize = min(max(0.003 / splat_radius, 1600.0 * f_avg_dist), 100.0);
        gl_PointSize = 16.0;//min( 0.012 / splat_radius, 100.0 );
        //gl_PointSize = min( 1600.0 * f_avg_dist, 100.0 );

        // Transform the vertex
        gl_Position = ftransform();

        // Transform the normal into eye space and normalize the result
        v_normal = normalize( gl_NormalMatrix * gl_Normal );

        // Calculate lighting
        vec3 light_dir;
        float light_dist;

        // Directional light?
        if ( gl_LightSource [0].position.w < 1.0 ) {
            /* Normalize the light's direction. Note that according to the
            OpenGL specification, the light is stored in eye space. Note that in
            the case of a directional light, the position field is actually direction */
            light_dir = normalize( gl_LightSource [0].position.xyz );
        // Point light?
        } else {
            vec3 lvec = gl_LightSource [0].position.xyz - gl_Position.xyz;
            light_dir = normalize( lvec );
            light_dist = length( lvec );
        }

        /* Compute the cos of the angle between the normal and light direction.
        The light is directional so the direction is constant for every vertex.
        Since these two are normalized the cosine is the dot product. We also
        need to clamp the result to the [0,1] range. */
        float n_dot_l = max( dot( v_normal, light_dir ), 0.0 );

        // Compute the diffuse term
        vec4 diffuse = gl_FrontMaterial.diffuse * gl_LightSource [0].diffuse;
        // Compute the ambient and global ambient terms
        vec4 ambient = gl_FrontMaterial.ambient * gl_LightSource [0].ambient;
        vec4 color = gl_LightModel.ambient * gl_FrontMaterial.ambient;

        // Compute the specular term if n_dot_l is > than 0
        if (n_dot_l > 0.0) {
            // Normalize the half-vector, and then compute the
            // cosine (dot product) with the normal
            float n_dot_hv = max( dot( v_normal, normalize( gl_LightSource [0].halfVector.xyz ) ), 0.0 );

            // Directional light?
            if (gl_LightSource [0].position.w < 1.0) {
                color += diffuse * n_dot_l + ambient;

                color += gl_FrontMaterial.specular * gl_LightSource [0].specular * pow( n_dot_hv, gl_FrontMaterial.shininess );

            // Point light?
            } else {
                float att = 1.0 / (gl_LightSource [0].constantAttenuation +
                                   gl_LightSource [0].linearAttenuation * light_dist +
                                   gl_LightSource [0].quadraticAttenuation * light_dist * light_dist);
                color += att * (diffuse * n_dot_l + ambient);
                color += att * gl_FrontMaterial.specular * gl_LightSource [0].specular * pow( n_dot_hv, gl_FrontMaterial.shininess );
            }
        }

        gl_FrontColor = color;
    }
}
